﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace XOAuthServer
{
	public partial class _default : System.Web.UI.Page
	{
		protected void Page_Init(object sender, EventArgs e)
		{
			XOAuth.KEY.SetCurrentDirectory(Helper.PemFolder());

			var client = ClientRaw.Read(Request.InputStream);
			object content;

			switch (client.head)
			{
				case "KEY":
					content = XOAuth.KEY.Public;
					break;
				case "CLIENT-KEY":
					if (client.body == null)
					{
						content = "?";
					}
					else
					{
						Session.Add("CLIENT-KEY", client.body);
						content = Session.SessionID;
					}
					break;
				case "TEST":
					content = client.GetBodyString();
					break;
				case "LOGIN":
					var loginMsg = LoginMessage.Parse(client.GetBodyString());
					content = loginMsg.Id;
					break;
				default:
					content = "OK";
					break;
			}

			if (!String.IsNullOrEmpty(Request.Headers["Origin"]))
			{
				var origin = Request.Headers["Origin"];
				if (origin == "null") origin = "*";
				Response.AppendHeader("Access-Control-Allow-Origin", origin);
			}
			Response.ContentType = "text/plain";
			Response.Write(content);
		}

		public struct ClientRaw
		{

			public ClientRaw(string h, byte[] b)
			{
				head = h;
				body = b;
			}
			public ClientRaw(byte[] h, byte[] b)
			{
				head = System.Text.Encoding.ASCII.GetString(h);
				body = b;
			}

			public readonly string head;
			public readonly byte[] body;

			public string GetBodyString()
			{
				if (body == null) return null;
				else if (body.Length < 1) return String.Empty;
				string s = String.Empty;
				if (body[0] == 0)
				{
					var base64 = System.Text.Encoding.ASCII.GetString(body, 1, body.Length - 1);
					var buf = Convert.FromBase64String(base64);
					s = System.Text.Encoding.UTF8.GetString(buf);
				} else
				{
					s = System.Text.Encoding.UTF8.GetString(body);
				}
				return HttpUtility.UrlDecode(s);
			}

			public override string ToString()
			{
				return IsEmpty ? "Empty" : String.Format("{0}:Body[{1}]", head, body == null ? -1 : body.Length);
			}

			public bool IsEmpty
			{
				get { return String.IsNullOrEmpty(head) && (body == null || body.Length < 1); }
			}

			public static readonly ClientRaw Empty = new ClientRaw();

			public static ClientRaw Read(byte[] buffer)
			{
				if (buffer == null || buffer.Length < 1) return ClientRaw.Empty;
				var headLen = buffer[0];

				var head = new byte[headLen];
				var body = new byte[buffer.Length - headLen - 1];
				Array.Copy(buffer, 1, head, 0, head.Length);
				Array.Copy(buffer, head.Length + 1, body, 0, body.Length);

				var client = new ClientRaw(head, body);
				return client;

			}
			public static ClientRaw Read(System.IO.Stream stream)
			{

				if (stream.Length < 1)
				{
					return ClientRaw.Empty;
				}

				using (System.IO.BinaryReader reader = new System.IO.BinaryReader(stream))
				{
					var headLen = reader.ReadByte();
					if (headLen < 0)
					{
						throw new ArgumentException("Invalid Input Data");
					}
					else if(headLen == 0)
					{
						var buf = new byte[stream.Length - stream.Position];
						stream.Read(buf, 0, buf.Length);
						buf = XOAuth.KEY.DecryptOaep(buf);
						return Read(buf);
					}

					byte[] head = reader.ReadBytes(headLen);

					int maxLen = 4096;
					var len = Math.Min(maxLen, stream.Length - 1 - head.Length);

					byte[] body;
					if (len <= 0) body = new byte[0];
					else
					{
						body = new byte[len];
						stream.Read(body, 0, body.Length);
					}

					var client = new ClientRaw(head, body);
					return client;
				}
			}
		}

		public struct LoginMessage
		{

			public LoginMessage(string id, string pwd, string salt)
			{
				Id = id;
				Password = pwd;
				Salt = salt;
			}

			public readonly string Id;
			public readonly string Password;
			public readonly string Salt;

			public static LoginMessage Parse(string loginSer)
			{
				var lines = loginSer.Split('\n');

				var msg = new LoginMessage(lines[0], lines[1], lines[2]);
				return msg;
			}

		}

	}
}